﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using gwBedrockApp;

namespace gwBedrockApp
{
    /// <summary>
    /// Create Application Instance
    /// </summary>
    partial class gwApplicationCreator
    {
        static gwApplicationCreator()
        {
            gwApplication.Instance = new LoginServer();
        }
    }

    //gate way server
    public class LoginServer : gwBedrockApp.gwApplication, IMessageOperator
    {
        #region private variable
        //buffer size
        int m_bufferLength;
        //message cache object
        MessageCache m_messageCache;
        //max database server count
        int m_maxDBCount = 0;
        //current database connection handle
        int m_curDBHandle = NetLib.INVALID_SESSION;
        //mysql server connection handle
        List<int> m_dbConnHandle = new List<int>();
        //gateway server connection handle
        int m_gatewayConnHandle = NetLib.INVALID_SESSION;
        //lock object
        private Object m_lock = new Object();
        #endregion

        #region constructor
        public LoginServer()
        {
            this.AppName = "LoginServer";
            this.AppVersion = "1.0.0.0";
            this.CompanyName = "GrayWind";

            m_bufferLength = 0;
        }
        #endregion

        #region virtual call
        private MessageCacheUnit tempUnit;
        /// <summary>
        /// override open() function
        /// </summary>
        /// <returns></returns>
        protected override bool Open()
        {
            base.Open();

            do
            {
                {
                    System.Console.WriteLine("Application Name:{0}", AppName);
                    System.Console.WriteLine("Application Verion:{0}", AppVersion);
                    System.Console.WriteLine("Company Name:{0}", CompanyName);

                    System.Console.WriteLine("Options:");
                    System.Console.WriteLine("         -i(IP. default 127.0.0.1)");
                    System.Console.WriteLine("         -p(Port. default 3376)");
                    System.Console.WriteLine("         -d(Max DBServer Count. default 5)");
                    System.Console.WriteLine("         -l(MaxListen. default 50)");
                    System.Console.WriteLine("         -t(I/O ThreadNum. default 1)");
                    System.Console.WriteLine("         -b(Buffer Length(kb). defalt 64)");
                    System.Console.WriteLine("         -g(GatewayServer IP. defalt 127.0.0.1)");
                    System.Console.WriteLine("         -gp(GatewayServer Port. defalt 3375)");

                    NetLib.create_service();
                    System.Console.WriteLine("Create Network Service Completely!");
                    m_strIP        = CommandLineArgs.GetString("i", "127.0.0.1");
                    m_iPort        = CommandLineArgs.GetInt("p", 3376);
                    int nListen    = CommandLineArgs.GetInt("l", 50);
                    int nTheads    = CommandLineArgs.GetInt("t", 1);
                    m_bufferLength = CommandLineArgs.GetInt("b", 64);
                    m_bufferLength *= 1024;

                    m_maxDBCount = CommandLineArgs.GetInt("d", 5);

                    string strGatewayIP = CommandLineArgs.GetString("g", "127.0.0.1");
                    int nGatewayPort = CommandLineArgs.GetInt("g", 3375);

                    System.Console.WriteLine("Parse Arguments Completely!");

                    System.Console.WriteLine("Initialize Network Service With:");
                    System.Console.WriteLine("Max Listen:{0}", nListen);
                    System.Console.WriteLine("Theads Number Of I/I Service:{0}", nTheads);
                    System.Console.WriteLine("Bytes Length Per Buffer:{0}", m_bufferLength);

                    NetLib.initialize_service(nTheads, nListen + m_maxDBCount, m_bufferLength);

                    m_messageCache = new MessageCache(m_bufferLength, 100);
                    tempUnit = new MessageCacheUnit(m_bufferLength);
                    if (m_messageCache == null)
                        break;

                    if (NetLib.is_service_init() == false)
                        break;

                    System.Console.WriteLine("Initialize Network Service Completely!");

                    NetLib.start_service();
                    System.Console.WriteLine("Start Network Service!");

                    if (NetLib.start_listen((UInt16)m_iPort, OnMessage) == false)
                        break;

                    System.Console.WriteLine("Listen On Port:{0}", m_iPort);

                    m_gatewayConnHandle = NetLib.start_connect(strGatewayIP, (UInt16)nGatewayPort, OnMessage);
                    if(m_gatewayConnHandle == NetLib.INVALID_SESSION)
                        break;

                    System.Console.WriteLine("Connect To Gateway Server...");
                    return true;
                }

            } while (false);

            return false;
        }

        /// <summary>
        /// override run() function
        /// </summary>
        protected override void Run()
        {
            ProcessMessage();
        }
        /// <summary>
        /// override close() function
        /// </summary>
        protected override void Close()
        {
            NetLib.close_listen();
            NetLib.terminate_service();
            NetLib.destroy_service();
            base.Close();
        }
        #endregion

        #region private function
        /// <summary>
        /// process message in the loop
        /// </summary>
        private void ProcessMessage()
        {
            m_messageCache.read(ref tempUnit);

            if (tempUnit.SessionId != -1)
            {
                NetMessageProcessor.ProcessMessage(this, tempUnit.SessionId, tempUnit.MsgId, tempUnit.Buffer, tempUnit.MsgBytes);
                tempUnit.discard();
            }
            else
                System.Threading.Thread.Sleep(1);
        }
        #endregion

        #region network callback
        /// <summary>
        /// store messages
        /// </summary>
        /// <param name="session_id">identifier of clients(such as login server, database server)</param>
        /// <param name="pMsgBuffer"></param>
        /// <param name="msgID"></param>
        /// <param name="msg_bytes"></param>
        public void StoreMessage(Int32 session_id, IntPtr pMsgBuffer, UInt32 msgID, UInt32 msg_bytes)
        {
            m_messageCache.write(session_id, msgID, msg_bytes, pMsgBuffer);
        }
		
		/// <summary>
        /// register to gateway server
        /// </summary>
        /// <param name="session_id"></param>
        public void RegisterToGateway(int session_id)
        {
            msgGWServer_Register register = new msgGWServer_Register(session_id, IP, Port, global.eServerType.ServerType_LoginServer);
            gwMessagePort.ProcessMessage(register);
        }

        /// <summary>
        /// request server list
        /// </summary>
        /// <param name="session_id"></param>
        public void RequestServerList(int session_id)
        {
            msgGWRequest_ServerInfo requestDB = new msgGWRequest_ServerInfo(session_id, global.eServerType.ServerType_DBServer);
            gwMessagePort.ProcessMessage(requestDB);
        }

        /// <summary>
        /// connect to the database server
        /// </summary>
        /// <param name="detail"></param>
        private void ConnectToDBServer(gatewayserver.ServerInfoFeedback.ServerDtail detail)
		{
            if (detail.Info.ServerType == global.eServerType.ServerType_DBServer)
            {
                lock (m_dbConnHandle)
                {
                    if (m_maxDBCount == 0)
                        return;

                    int handle = NetLib.start_connect(detail.Info.IpAddr, (UInt16)detail.Info.Port, OnMessage);
                    if (handle != NetLib.INVALID_SESSION)
                    {
                        m_dbConnHandle.Add(handle);
                        m_maxDBCount--;
                    }
                }
             }
		}
		
		/// <summary>
        /// save server list
        /// </summary>
        /// <param name="sf"></param>
        public void SaveServerList(gatewayserver.ServerInfoFeedback sf)
        {
            foreach (gatewayserver.ServerInfoFeedback.ServerDtail detail in sf.InfoList)
            {
                if (sf.ServerType == global.eServerType.ServerType_DBServer)
                    ConnectToDBServer(detail);
            }
        }

        /// <summary>
        /// notify to client
        /// </summary>
        /// <param name="session_id"></param>
        public void NotifyToClient(int session_id)
        {
			msgGBServer_Notify msg = new msgGBServer_Notify(session_id, global.eServerType.ServerType_LoginServer);
            gwMessagePort.ProcessMessage(msg);
        }
		
        /// <summary>
        /// process incoming message
        /// </summary>
        /// <param name="session_id"></param>
        /// <param name="pMsgBuffer"></param>
        /// <param name="msgID"></param>
        /// <param name="msg_bytes"></param>
        /// <param name="type"></param>
        /// <param name="error_code"></param>
        private static void OnMessage(Int32 session_id, IntPtr pMsgBuffer, UInt32 msgID, UInt32 msg_bytes, Int32 type, Int32 error_code)
        {
            NetMsgProcDispatcher.dipatch<LoginServer>((LoginServer)gwApplication.Instance, type, session_id, pMsgBuffer, msgID, msg_bytes, error_code);
        }

		/// <summary>
		/// Gets the DB handle.
		/// </summary>
		public int GetDBHandle()
		{
			lock (m_dbConnHandle)
            {
                while (m_dbConnHandle.Count > 0)
                {
                    m_curDBHandle = (++m_curDBHandle) % m_dbConnHandle.Count;
                    if (NetLib.is_alive(m_curDBHandle) == true)
                        return m_curDBHandle;
                    else
                        m_dbConnHandle.RemoveAt(m_curDBHandle);
                }
            }
			
			return NetLib.INVALID_SESSION;
		}

        /// <summary>
        /// remove account info from the cache
        /// </summary>
        /// <param name="session_id"></param>
        public void RemoveAccountCache(int session_id)
        {
            m_loginManager.Remove(session_id);
        }
		
		/// <summary>
        /// generate passport
        /// </summary>
        /// <param name="usr id"></param>
		public int GeneratePassport(int usr_id)
		{
			return m_passport.GeneratePassport(usr_id);
		}
		
		/// <summary>
        /// remove passport
        /// </summary>
        /// <param name="usr id"></param>
		public void RemovePassport(int usr_id)
		{
			m_passport.RemovePassport(usr_id);
		}
		
		/// <summary>
        /// check passport
        /// </summary>
        /// <param name="usr id"></param>
        /// <param name="passport"></param>
		public bool CheckPassport(int usr_id, int passport)
		{
			return m_passport.CheckPassport(usr_id, passport);
		}
        #endregion

        #region property
        //server ip
        private string m_strIP;
        /// <summary>
        /// server ip address
        /// </summary>
        public string IP
        {
            get
            {
                return m_strIP;
            }
            set
            {
                m_strIP = value;
            }
        }
        //server port
        private int m_iPort;
        /// <summary>
        /// server port
        /// </summary>
        public int Port
        {
            get
            {
                return m_iPort;
            }
            set
            {
                m_iPort = value;
            }
        }

        //passport verify
        PassportVerify m_passport = new PassportVerify();
        /// <summary>
        /// passport verify
        /// </summary>
        public PassportVerify Passport
        {
            get
            {
                return m_passport;
            }
            private set
            {
                m_passport = value;
            }
        }
        //user login manager
        UsrLoginManager m_loginManager = new UsrLoginManager(10000);
        /// <summary>
        /// user login manager
        /// </summary>
        public UsrLoginManager LoginManager
        {
            get
            {
                return m_loginManager;
            }
            private set
            {
                m_loginManager = value;
            }
        }
        #endregion
    }
}
